package commons.util;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.SortedMap;
import java.util.TreeMap;

public class JavaTimeApi {
  static String dateStr = "2023-08-14";
  static String datePattern = "yyyy-MM-dd";
  static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(datePattern);
  static String dateTimePattern = datePattern + " HH:mm:ss";
  static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimePattern);

  static ZoneOffset offset = ZoneOffset.ofHours(8);
  static LocalDate date = LocalDate.parse(dateStr, dateFormatter);
  static int seconds = 1692002517;

  @Retention(RetentionPolicy.RUNTIME)
  @interface order {
    int value();
  }

  private static void printDateTime(LocalDateTime time, String message) {
    if (message == null) {
      message = "";
    }
    System.out.println(message + time.format(dateTimeFormatter));
  }

  @order(1)
  static void startOfDay() {
    LocalDateTime time = date.atStartOfDay();
    printDateTime(time, "指定日期零点：");
  }

  @order(2)
  static void endOfDay() {
    LocalDateTime time = date.plusDays(1).atStartOfDay().minusSeconds(1);
    printDateTime(time, "指定日期最后一秒：");
  }

  @order(3)
  static void whichDay() {
    int res = date.get(ChronoField.DAY_OF_YEAR);
    System.out.println("某天是该年的第几天：" + res);
  }

  @order(4)
  static void nextMonthFirstDay() {
    LocalDate res = date.plusMonths(1).withDayOfMonth(1);
    System.out.println("下个月的第一天：" + res);
  }

  @order(5)
  static void nextMonthLastDay() {
    LocalDate res = date.plusMonths(2)
        .withDayOfMonth(1)
        .minusDays(1);
    System.out.println("下个月的最后一天：" + res);
  }

  @order(6)
  static void millisOfTheEndOfDay() {
    Instant res = date.atStartOfDay().plusDays(1).minusSeconds(1).toInstant(offset);
    System.out.println("某天最后一秒对应时间戳：" + res.toEpochMilli());
  }

  @order(7)
  static void dateOfSeconds() {
    LocalDateTime res = LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds), offset);
    printDateTime(res, "秒对应日期：");
  }

  @order(8)
  static void lengthOfMonth() {
    int year = 2023;
    int month = 2;
    int res = LocalDate.of(year, month, 1).lengthOfMonth();
    System.out.println("某个月长度：" + res);
  }

  @order(9)
  static void diffDateDetail() {
    String date1 = "2022-01-12";
    String date2 = "2023-08-14";
    LocalDate from = LocalDate.parse(date1, dateFormatter);
    LocalDate to = LocalDate.parse(date2, dateFormatter);
    Period period = from.until(to);
    long years = period.getYears();
    long months = period.getMonths();
    long days = period.getDays();
    System.out.println("Years: " + years);
    System.out.println("Months: " + months);
    System.out.println("Days: " + days);
  }

  @order(10)
  static void diffDate() {
    String date1 = "1990-01-08";
    String date2 = "2023-08-16";
    LocalDate from = LocalDate.parse(date1, dateFormatter);
    LocalDate to = LocalDate.parse(date2, dateFormatter);
    long res = from.until(to, ChronoUnit.DAYS);
    System.out.println("两个日期间隔多少天：" + res);
  }

  public static void main(String[] args) {
    SortedMap<Integer, Method> methods = new TreeMap<>();
    for (Method method : JavaTimeApi.class.getDeclaredMethods()) {
      if (method.isAnnotationPresent(order.class)) {
        methods.put(method.getAnnotation(order.class).value(), method);
      }
    }
    methods.values().forEach(method -> {
      try {
        method.invoke(null);
      } catch (Exception e) {
        e.printStackTrace();
      }
    });
  }
}
